package model.enemies;

import java.util.List;

import model.surface.PathPoint;
import model.surface.Scale;
import model.utils.Speed;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;

/**
 * Abstract class implements all enemies methods for the game.
 * 
 * @author EvilTeam
 *
 */
public abstract class EnemySprite implements IEnemy {

	private static final int NUMBER_OF_COLUMNS_IN_SPRITE_IMAGE = 4;
	private static final int START_DIRECTION = Speed.DIRECTION_RIGHT;

	private Scale scale = Scale.getInstanceOfScaleClass();
	private int currentFrame;
	private int currentDirection = START_DIRECTION;
	private Bitmap bitmapImage, scaledImage;
	private Speed speed;
	private float xAxisPoint, yAxisPoint;
	private int currentFrameHeight, currentFrameWidth;
	private int helathPoints;
	private List<PathPoint> pathArray;

	/**
	 * Draw enemy facing the right direction.
	 */
	@Override
	public void draw(Canvas canvas) {
		if (this.helathPoints > 0) {
			int xStartPoint = currentFrame * currentFrameWidth;
			int yStartPoint = currentDirection * currentFrameHeight;
			Rect sourceRectangular = new Rect(xStartPoint, yStartPoint,
					xStartPoint + this.getWidth(), yStartPoint
							+ this.getHeight());
			Rect destinationRectangular = new Rect((int) xAxisPoint
					- this.getWidth() / 2, (int) yAxisPoint - this.getHeight(),
					(int) xAxisPoint + this.getWidth() / 2, (int) yAxisPoint);
			canvas.drawBitmap(scaledImage, sourceRectangular,
					destinationRectangular, null);
		}
	}

	/**
	 * Update the location of the enemy.
	 */
	@Override
	public void updateMyLocation() {
		checkForPathCollisions();
		this.xAxisPoint += (speed.getxVelocity() * speed.getxStartDirection());
		this.yAxisPoint += (speed.getyVelocity() * speed.getyStartDirection());
		currentFrame = ++currentFrame % NUMBER_OF_COLUMNS_IN_SPRITE_IMAGE;
	}

	/**
	 * Checks if the enemy needs to turn and if yes turns him the right way.
	 */
	private void checkForPathCollisions() {

		float currentMovingSpeed = 0;

		if (speed.getxVelocity() != 0) {
			currentMovingSpeed = speed.getxVelocity();
		} else {
			currentMovingSpeed = speed.getyVelocity();
		}

		for (int i = 1; i < pathArray.size() - 1; i++) {

			if (pathArray.get(i).isInThePathPoint(xAxisPoint, yAxisPoint)) {
				switch (pathArray.get(i).getDirection()) {
				case Speed.DIRECTION_DOWN:
					if (pathArray.get(i + 1).getyPoint() > yAxisPoint)
						speed.resetXYAxisDirections();
					speed.setyVelocity(currentMovingSpeed);
					speed.setxVelocity(0);
					currentDirection = Speed.DIRECTION_DOWN;
					break;
				case Speed.DIRECTION_LEFT:
					if (pathArray.get(i + 1).getxPoint() < xAxisPoint) {
						speed.resetXYAxisDirections();
						speed.changeXAxisDirection();
					}
					speed.setyVelocity(0);
					speed.setxVelocity(currentMovingSpeed);
					currentDirection = Speed.DIRECTION_LEFT;
					break;
				case Speed.DIRECTION_RIGHT:
					if (pathArray.get(i + 1).getxPoint() > xAxisPoint)
						speed.resetXYAxisDirections();
					speed.setyVelocity(0);
					speed.setxVelocity(currentMovingSpeed);
					currentDirection = Speed.DIRECTION_RIGHT;
					break;
				case Speed.DIRECTION_UP:
					if (pathArray.get(i + 1).getyPoint() < yAxisPoint) {
						speed.resetXYAxisDirections();
						speed.changeYAxisDirection();
					}
					speed.setyVelocity(currentMovingSpeed);
					speed.setxVelocity(0);
					currentDirection = Speed.DIRECTION_UP;
					break;
				}
			}
		}
	}

	@Override
	public void clearOldBitmap(Canvas canvas) {
		canvas.drawColor(0, Mode.CLEAR);
	}

	@Override
	public Speed getSpeed() {
		return speed;
	}

	@Override
	public void setSpeed(Speed speed) {
		if (speed != null)
			this.speed = speed;
	}

	@Override
	public float getX() {
		return xAxisPoint;
	}

	public void setX(float x) {
		if (x > 0)
			this.xAxisPoint = x;
	}

	@Override
	public float getY() {
		return yAxisPoint;
	}

	public void setY(float y) {
		if (y > 0)
			this.yAxisPoint = y;
	}

	@Override
	public int getHealthPoints() {
		return helathPoints;
	}

	@Override
	public void setHealthPoints(int hp) {
		this.helathPoints = hp;
	}

	public Bitmap getImage() {
		return bitmapImage;
	}

	/**
	 * Scale down enemy image for different screens.
	 * 
	 * @param image
	 */
	public void setImage(Bitmap image) {
		if (image != null) {
			this.bitmapImage = image;
			scaledImage = Bitmap.createScaledBitmap(this.bitmapImage,
					(int) scale.getScaledHeightForImages(),
					(int) scale.getScaledWidthForImages(), true);
			setCurrentFrameHeight();
			setCurrentFrameWidth();
		}
	}

	@Override
	public int getHeight() {
		return currentFrameHeight;
	}

	@Override
	public int getWidth() {
		return currentFrameWidth;
	}

	private void setCurrentFrameHeight() {
		this.currentFrameHeight = scaledImage.getHeight()
				/ NUMBER_OF_COLUMNS_IN_SPRITE_IMAGE;
	}

	private void setCurrentFrameWidth() {
		this.currentFrameWidth = scaledImage.getWidth()
				/ NUMBER_OF_COLUMNS_IN_SPRITE_IMAGE;
	}

	public void setPathArray(List<PathPoint> pathArray) {
		if (pathArray != null)
			this.pathArray = pathArray;
	}
}
